//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Base/Platform/Platform.h"

namespace Engine
{
namespace Base
{

	template <typename T>
	struct Time;

	template <typename T>
	struct TimeProfiler;



	//
	// Time
	//
	
	template <>
	struct Time <double>
	{
	// types
	public:
		typedef double					value_t;
		typedef TimeProfiler< double >	prefiler_t;
		typedef Time< double >			Self;


	// variables
	private:
		value_t		_time;


	// methods
	public:
		Time () : _time(0.0) {}

		explicit
		Time (value_t value) : _time(value) {}

		Self &	FromTime (const Time<uint64> &time);

		Self &	FromSec (const double &value)			{ _time = value;			return *this; }
		Self &	FromMilliSec (const double &value)		{ _time = value * 1.0e-3;	return *this; }
		Self &	FromMicroSec (const double &value)		{ _time = value * 1.0e-6;	return *this; }
		Self &	FromNanoSec (const double &value)		{ _time = value * 1.0e-9;	return *this; }

		double	GetSec ()		const					{ return _time; }
		double	GetMilliSec ()	const					{ return _time * 1.0e3; }
		double	GetMicroSec ()	const					{ return _time * 1.0e6; }
		double	GetNanoSec ()	const					{ return _time * 1.0e9; }

		Self &	operator += (const Self &right)			{ _time += right._time;  return *this; }
		Self &	operator -= (const Self &right)			{ _time -= right._time;  return *this; }

		Self	operator +  (const Self &right)	const	{ return ( Self(*this) += right ); }
		Self	operator -  (const Self &right)	const	{ return ( Self(*this) -= right ); }

		Time<uint64>	ToUint64 () const;
	};



	//
	// Time
	//
	
	template <>
	struct Time <uint64>
	{
	// types
	public:
		typedef uint64					value_t;
		typedef TimeProfiler< uint64 >	prefiler_t;
		typedef Time< uint64 >			Self;


	// variables
	private:
		value_t		_time;


	// methods
	public:
		Time () : _time(0) {}

		explicit
		Time (value_t value) : _time(value) {}

		Self &	FromTime (const Time<double> &time)		{ return FromNanoSec( uint64( time.GetNanoSec() + 0.5 ) ); }

		Self &	FromMilliSec (const uint64 &value)		{ _time = value * 1000000ull;	return *this; }
		Self &	FromMicroSec (const uint64 &value)		{ _time = value * 1000ull;		return *this; }
		Self &	FromNanoSec (const uint64 &value)		{ _time = value;				return *this; }

		uint64	GetNanoSec ()					const	{ return _time; }

		Self &	operator += (const Self &right)			{ _time += right._time;  return *this; }
		Self &	operator -= (const Self &right)			{ _time -= right._time;  return *this; }

		Self	operator +  (const Self &right)	const	{ return ( Self(*this) += right ); }
		Self	operator -  (const Self &right)	const	{ return ( Self(*this) -= right ); }

		Time<double>	ToDouble ()				const	{ return Time<double>().FromTime( *this ); }
	};
	
	
	// ToUint64
	inline Time<uint64>  Time<double>::ToUint64 () const
	{
		return Time<uint64>().FromTime( *this );
	}

	// FromTime
	inline Time<double> & Time<double>::FromTime (const Time<uint64> &time)
	{
		return FromNanoSec( double( time.GetNanoSec() ) );
	}



	//
	// Time Profiler
	//
	
	template <>
	struct TimeProfiler <double>
	{
	// types
	public:
		typedef double					value_t;
		typedef Time< double >			time_t;
		typedef TimeProfiler< double >	Self;


	// variables
	private:
		PerfomanceTimer	_timer;
		time_t			_start;


	// methods
	public:
		TimeProfiler (bool start = false)
		{
			if ( start ) {
				Start();
			}
		}

		void Start ()
		{
			_start.FromSec( _timer.GetTime() );
		}


		time_t GetTimeDelta () const
		{
			return time_t().FromSec( _timer.GetTime() - _start.GetSec() );
		}

		time_t GetStartTime () const
		{
			return _start;
		}
	};



	//
	// Time Profiler
	//

	template <>
	struct TimeProfiler <uint64>
	{
	// types
	public:
		typedef uint64					value_t;
		typedef Time< uint64 >			time_t;
		typedef TimeProfiler< uint64 >	Self;


	// variables
	private:
		PerfomanceTimer	_timer;
		time_t			_start;


	// methods
	public:
		TimeProfiler (bool start = false)
		{
			if ( start ) {
				Start();
			}
		}

		void Start ()
		{
			_start.FromMicroSec( _timer.GetTimeMicroSec() );
		}


		time_t GetTimeDelta () const
		{
			return time_t().FromNanoSec( _timer.GetTimeMicroSec() * 1000 - _start.GetNanoSec() );
		}

		time_t GetStartTIme () const
		{
			return _start;
		}
	};


}	// Base
}	// Engine